local g
if not FileIO.pwd():endsWith("packages/freekill-core") then
  FileIO.cd("packages/freekill-core")
  g=require "server.gameevent"
  FileIO.cd("../..")
else
  g=require "server.gameevent"
end
--local Pe=require "packages/jbs2/pokgame/pokegegine"
local T = require "packages/jbs/record/Theorem"
local GameEvent=g:subclass("pokegemsGameEvent")
local pokepool=require "packages/jbs2/pokgame/pokemonlist"

GameEvent.PokeGemsRound=300
GameEvent.PVEDrawInitial=303
GameEvent.PokeGemsTurn=301
GameEvent.PokeGemsPhase=302



local function drawInit(room, player, n)
  -- TODO: need a new function to call the UI
  local cardIds = room:getNCards(n)
  player:addCards(Player.Hand, cardIds)
  for _, id in ipairs(cardIds) do
    Fk:filterCard(id, player)
  end
  local move_to_notify = {}   ---@type CardsMoveStruct
  move_to_notify.toArea = Card.PlayerHand
  move_to_notify.to = player.id
  move_to_notify.moveInfo = {}
  move_to_notify.moveReason = fk.ReasonDraw
  for _, id in ipairs(cardIds) do
    table.insert(move_to_notify.moveInfo,
    { cardId = id, fromArea = Card.DrawPile })
  end
  room:notifyMoveCards(nil, {move_to_notify})

  for _, id in ipairs(cardIds) do
    room:setCardArea(id, Card.PlayerHand, player.id)
  end
end

local function discardInit(room, player)
  local cardIds = player:getCardIds(Player.Hand)
  player:removeCards(Player.Hand, cardIds)
  table.insertTable(room.draw_pile, cardIds)
  for _, id in ipairs(cardIds) do
    Fk:filterCard(id, nil)
  end

  local move_to_notify = {}   ---@type CardsMoveStruct
  move_to_notify.from = player.id
  move_to_notify.toArea = Card.DrawPile
  move_to_notify.moveInfo = {}
  move_to_notify.moveReason = fk.ReasonJustMove
  for _, id in ipairs(cardIds) do
    table.insert(move_to_notify.moveInfo,
    { cardId = id, fromArea = Card.PlayerHand })
  end
  room:notifyMoveCards(nil, {move_to_notify})

  for _, id in ipairs(cardIds) do
    room:setCardArea(id, Card.DrawPile, nil)
  end
end

GameEvent.functions[GameEvent.PVEDrawInitial] = function(self)
  local room = self.room

  local luck_data = {
    drawInit = drawInit,
    discardInit = discardInit,
    playerList = table.map(room.alive_players, Util.IdMapper),
  }

  for _, player in ipairs(room.alive_players) do
    local draw_data = { num = 0}
    room.logic:trigger(fk.DrawInitialCards, player, draw_data)
    luck_data[player.id] = draw_data
    luck_data[player.id].luckTime = 0
    if player.id < 0 then -- Robot
      luck_data[player.id].luckTime = 0
    end
    if draw_data.num > 0 then
      drawInit(room, player, draw_data.num)
    end
  end

  if room:getSettings('luckTime') <= 0 then
    for _, player in ipairs(room.alive_players) do
      local draw_data = luck_data[player.id]
      draw_data.luckTime = nil
      room.logic:trigger(fk.AfterDrawInitialCards, player, draw_data)
    end
    return
  end

  room:setTag("LuckCardData", luck_data)
  room:notifyMoveFocus(room.alive_players, "AskForLuckCard")
  room:doBroadcastNotify("AskForLuckCard", 1)

  local remainTime = room.timeout + 1
  local currentTime = os.time()
  local elapsed = 0

  for _, id in ipairs(luck_data.playerList) do
    local pl = room:getPlayerById(id)
    if luck_data[id].luckTime > 0 then
      pl.serverplayer:setThinking(true)
    end
  end

  while true do
    elapsed = os.time() - currentTime
    if remainTime - elapsed <= 0 then
      break
    end

    -- local ldata = room:getTag("LuckCardData")
    local ldata = luck_data

    if table.every(ldata.playerList, function(id)
      return ldata[id].luckTime == 0
    end) then
      break
    end

    for _, id in ipairs(ldata.playerList) do
      local pl = room:getPlayerById(id)
      if pl._splayer:getState() ~= fk.Player_Online then
        ldata[id].luckTime = 0
        pl.serverplayer:setThinking(false)
      end
    end

    -- room:setTag("LuckCardData", ldata)

    room:checkNoHuman()

    coroutine.yield("__handleRequest", (remainTime - elapsed) * 1000)
  end

  for _, player in ipairs(room.alive_players) do
    local draw_data = luck_data[player.id]
    draw_data.luckTime = nil
    room.logic:trigger(fk.AfterDrawInitialCards, player, draw_data)
  end

  room:removeTag("LuckCardData")
end











function GameEvent:actionround()
  local room = self.room
  local p
  local nextTurnOwner
  local skipRoundPlus = false
  repeat
    nextTurnOwner = nil
    skipRoundPlus = false
    p = room.current
    GameEvent.Turn:create(p):exec()
    if room.game_finished then break end

    local changingData = { from = room.current, to = room.current:getNextAlive(true, nil, true), skipRoundPlus = false }
    room.logic:trigger(fk.EventTurnChanging, room.current, changingData, true)

    skipRoundPlus = changingData.skipRoundPlus
    local nextAlive = room.current:getNextAlive(true, nil, true)
    if nextAlive ~= changingData.to and not changingData.to.dead then
      room.current = changingData.to
      nextTurnOwner = changingData.to
    else
      room.current = nextAlive
    end
  until p.seat >= (nextTurnOwner or p:getNextAlive(true, nil, true)).seat and not skipRoundPlus
end

GameEvent.functions[GameEvent.PokeGemsRound] = function(self)
    local room = self.room
    local logic = room.logic
    local p
  
    local isFirstRound = room:getTag("FirstRound")
    if isFirstRound then
      room:setTag("FirstRound", false)
    end
  
    local roundCount = room:getTag("RoundCount")
    roundCount = roundCount + 1
    room:setTag("RoundCount",  roundCount)
    room:doBroadcastNotify("UpdateRoundNum", roundCount)
    -- 强行平局 防止can_trigger报错导致瞬间几十万轮卡炸服务器
    if roundCount >= 9999 then
      room:gameOver("")
    end
  
    if isFirstRound then

      logic:trigger(fk.GameStart, room.current)
    end
  
    logic:trigger(fk.RoundStart, room.current)
   
    repeat
      p = room.current
      GameEvent(GameEvent.PokeGemsTurn, p):exec()
      if room.game_finished then break end
      room.current = p:getNextAlive(true, nil, true)
    until p.seat >= p:getNextAlive(true, nil, true).seat
  

  
  
    logic:trigger(fk.RoundEnd, p)
   end
GameEvent.cleaners[GameEvent.PokeGemsRound] = function(self)
    local room = self.room
  
    for _, p in ipairs(room.players) do
      p:setCardUseHistory("", 0, Player.HistoryRound)
      p:setSkillUseHistory("", 0, Player.HistoryRound)
      for name, _ in pairs(p.mark) do
        if name:find("-round", 1, true) then
          room:setPlayerMark(p, name, 0)
        end
        if name:find("-effectround", 1, true) then
          room:removePlayerMark(p, name, 1)
        end
      end
    end
  

  
    for _, p in ipairs(room.players) do
      p:filterHandcards()
      room:broadcastProperty(p, "MaxCards")
    end
    if room:getTag("pokegems_end") then
      local id=0
      --获得最高分的玩家
      --获取最高分
      for _,player in ipairs(room.players) do
        if player:getMark("@pokegems-score")>id then
          id=player:getMark("@pokegems-score")
        end
      end
      --获得赢家列表
      local winner=table.filter(room.players,function(player)
        return player:getMark("@pokegems-score")==id
      end)
      for _,p in ipairs(winner) do
        p.role="renegade"
      end
      room:gameOver("renegade")
    end
end

GameEvent.prepare_funcs[GameEvent.PokeGemsTurn] = function(self)
    local room = self.room
    local logic = room.logic
    local player = room.current
  
    if player.rest > 0 and player.rest < 999 then
      room:setPlayerRest(player, player.rest - 1)
      if player.rest == 0 and player.dead then
        room:revivePlayer(player, true, "rest")
      else
        room:delay(50)
      end
    end
  
    if player.dead then return true end
  
    room:sendLog{ type = "$AppendSeparator" }
  
    if not player.faceup then
      player:turnOver()
      return true
    end
  
    return logic:trigger(fk.BeforeTurnStart, player)
end
  
GameEvent.functions[GameEvent.PokeGemsTurn] = function(self)
    local room = self.room
    local total_gems=room.total_gems
    local logic = room.logic
    local pool=room.pool
    local player=room.current
    room:notifyMoveFocus(player,"pokemon_gems")
    room:delay(300)
    room.timeout = 60
    local list=player.gemlist or {1,7,7,7,7,7}
    local buff=player.buff_table
    local pool_gems=room.gems_tool
    local gemslist = {}
    local gemdata={}
    for i = 1, 6 do
        table.insert(gemslist, list[i] + buff[i])
    end
    if player.id>0 then
      local othersid=table.map(room:getOtherPlayers(player),function (p)
        return p.id
        
      end)
      gemdata[player.id]={
        total_gems,gemslist,
       pool,true
      }
      for _,id in ipairs(othersid) do
        gemdata[id]={
          total_gems,gemslist,
          pool,false
        }
      end
      local result=room:askForMiniGame(room.players, "璀璨宝石","pokemongems_sel", gemdata)

    if  player.reply_ready then
      local choice = json.decode(player.client_reply) 
      local pokeit=choice[1]--由购买宝可梦的name，cost，value，score，evolve组成
      local ballit=choice[2]--由购买精灵球数组成的表
      --dbg()
     
      pool_gems:playerchoice(player,pokeit,ballit)
      room:notifyMoveFocus(player,"pokemon_gems")

      end
    else
      --local card=room:askForResponse(player,'.',"nullification", "#jbs_uno-ask", true)
  
    end

    local phase_table = {Player.RoundStart,
    Player.Start,

     Player.Finish, Player.NotActive,
   }

    --[[
    local phase_table = {Player.RoundStart,
       Player.Start,
       Player.Play,
        Player.Finish, Player.NotActive,
      }
    logic:trigger(fk.TurnStart, room.current)

    room.current:play(phase_table)
    --]]
end
  
  GameEvent.cleaners[GameEvent.PokeGemsTurn] = function(self)
    local room = self.room

    local current = room.current
    local logic = room.logic
    if self.interrupted then
      if current.phase ~= Player.NotActive then
        local current_phase = current.phase
        current.phase = Player.PhaseNone
        logic:trigger(fk.EventPhaseChanging, current,
          { from = current_phase, to = Player.NotActive }, true)
        current.phase = Player.NotActive
        room:broadcastProperty(current, "phase")
        logic:trigger(fk.EventPhaseStart, current, nil, true)
      end
  
      current.skipped_phases = {}
    end
  
    logic:trigger(fk.TurnEnd, current, nil, self.interrupted)
    logic:trigger(fk.AfterTurnEnd, current, nil, self.interrupted)
  
    for _, p in ipairs(room.players) do
      p:setCardUseHistory("", 0, Player.HistoryTurn)
      p:setSkillUseHistory("", 0, Player.HistoryTurn)
      for name, _ in pairs(p.mark) do
        if name:find("-turn", 1, true) then
          room:setPlayerMark(p, name, 0)
        end
      end
    end
  
    for cid, cmark in pairs(room.card_marks) do
      for name, _ in pairs(cmark) do
        if name:find("-turn", 1, true) then
          room:setCardMark(Fk:getCardById(cid), name, 0)
        end
      end
    end
  
    for _, p in ipairs(room.players) do
      p:filterHandcards()
      room:broadcastProperty(p, "MaxCards")
    end
  end
  
  GameEvent.functions[GameEvent.PokeGemsPhase] = function(self)
    local room = self.room
    local logic = room.logic
  
    local player = self.data[1] ---@type Player
    if not logic:trigger(fk.EventPhaseStart, player) then
      if player.phase ~= Player.NotActive then
        logic:trigger(fk.EventPhaseProceeding, player)
  
        switch(player.phase, {
        [Player.PhaseNone] = function()
          error("You should never proceed PhaseNone")
        end,
        [Player.RoundStart] = function()
  
        end,
        [Player.Start] = function()
  
        end,
        [Player.Judge] = function()
          local cards = player:getCardIds(Player.Judge)
          while #cards > 0 do
            local cid = table.remove(cards)
            if not cid then return end
            local card = player:removeVirtualEquip(cid)
            if not card then
              card = Fk:getCardById(cid)
            end
            if table.contains(player:getCardIds(Player.Judge), cid) then
              room:moveCardTo(card, Card.Processing, nil, fk.ReasonPut, self.name)
  
              ---@type CardEffectEvent
              local effect_data = {
                card = card,
                to = player.id,
                tos = { {player.id} },
              }
              room:doCardEffect(effect_data)
              if effect_data.isCancellOut and card.skill then
                card.skill:onNullified(room, effect_data)
              end
            end
          end
        end,
        [Player.Draw] = function()
          local data = {
            n = 2
          }
          room.logic:trigger(fk.DrawNCards, player, data)
          room:drawCards(player, data.n, "game_rule")
          room.logic:trigger(fk.AfterDrawNCards, player, data)
        end,
        [Player.Play] = function()
          player._play_phase_end = false
          while not player.dead do
            logic:trigger(fk.StartPlayCard, player, nil, true)
            room:notifyMoveFocus(player, "PlayCard")
            local result = room:doRequest(player, "PlayCard", player.id)
            if result == "" then break end
  
            local useResult = room:handleUseCardReply(player, result)
            if type(useResult) == "table" then
              room:useCard(useResult)
            end
  
            if player._play_phase_end then
              player._play_phase_end = false
              break
            end
          end
        end,
        [Player.Discard] = function()
          local discardNum = #table.filter(
            player:getCardIds(Player.Hand), function(id)
              local card = Fk:getCardById(id)
              return table.every(room.status_skills[MaxCardsSkill] or Util.DummyTable, function(skill)
                return not skill:excludeFrom(player, card)
              end)
            end
          ) - player:getMaxCards()
          if discardNum > 0 then
            room:askForDiscard(player, discardNum, discardNum, false, "game_rule", false)
          end
        end,
        [Player.Finish] = function()
  
        end,
        })
      end
    end
  end
  
  GameEvent.cleaners[GameEvent.PokeGemsPhase] = function(self)
    local room = self.room
    local player = self.data[1]
    local logic = room.logic
  
    if player.phase ~= Player.NotActive then
      logic:trigger(fk.EventPhaseEnd, player, nil, self.interrupted)
      logic:trigger(fk.AfterPhaseEnd, player, nil, self.interrupted)
    else
      player.skipped_phases = {}
    end
  
    for _, p in ipairs(room.players) do
      p:setCardUseHistory("", 0, Player.HistoryPhase)
      p:setSkillUseHistory("", 0, Player.HistoryPhase)
      for name, _ in pairs(p.mark) do
        if name:find("-phase", 1, true) then
          room:setPlayerMark(p, name, 0)
        end
      end
    end
  
    for cid, cmark in pairs(room.card_marks) do
      for name, _ in pairs(cmark) do
        if name:find("-phase", 1, true) then
          room:setCardMark(Fk:getCardById(cid), name, 0)
        end
      end
    end
  
    for _, p in ipairs(room.players) do
      p:filterHandcards()
      room:broadcastProperty(p, "MaxCards")
    end
  end


return GameEvent